<?php
/**
 * This file defines the {@see \BF\Drawing\Color} class.
 *
 * @author     Kado <ulfikado@gmail.com>
 * @category   Beluga PHP5.3+ Framework
 * @package    BF\Drawing
 * @since      2015-01-31 00:29
 * @subpackage Core
 * @version    0.1
 */

namespace BF\Drawing
{

   /**
    * Defines all informations of a color. (R, G, B, Opacity/Alpha, GD).
    *
    * @since    v0.1
    * @property integer $R     The red color part.
    * @property integer $Red   Alias of 'R'
    * @property integer $G     The green color part.
    * @property integer $Green Alias of 'G'
    * @property integer $B     The blue color part.
    * @property integer $Blue  Alias alias 'B'
    * @property string  $Hex   Hexadecimal color definition #rrggbb
    * @property array   $Rgb   Array numeric array(r, g, b)
    */
   class Color
   {

      # <editor-fold defaultstate="collapsed" desc=" - - -   P R O T E C T E D   F I E L D S   - - - - - - - - - - - - - - - - - - - -">

      /**
       * Array with keys 'red', 'green', 'blue', 'hex', 'opacity', 'alpha'
       *
       * @var array
       */
      protected $data;

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - >   P U B L I C   C O N S T R U C T O R   - - - - - - - - - - - - - - - - - -">

      /**
       * Inits a new instance.
       *
       * @param string|int|array $colorDefinition Color
       * @param integer          $opacity         The color opacity in percent 0-100 (default=null)
       */
      public function __construct( $colorDefinition = '#ffffff', $opacity = null )
      {
         if ( false === ( $rgb = \BF\Drawing\ColorTool::Color2Rgb( $colorDefinition ) ) )
         {
            $rgb = array( 0, 0, 0 );
         }
         $this->data = array( 'red' => $rgb[ 0 ], 'green' => $rgb[ 1 ], 'blue' => $rgb[ 2 ] );
         if ( \is_null( $opacity ) )
         {
            $this->data[ 'opacity' ] = null;
         }
         elseif ( $opacity <= 0 )
         {
            $this->data[ 'opacity' ] = 0;
         }
         elseif ( $opacity >= 100 )
         {
            $this->data[ 'opacity' ] = 100;
         }
         else
         {
            $this->data[ 'opacity' ] = $opacity;
         }
         $this->data[ 'hex' ] = \BF\Drawing\ColorTool::Rgb2Hex(
            $this->data[ 'red' ],
            $this->data[ 'green' ],
            $this->data[ 'blue' ]
         );
         if ( \is_null( $opacity ) )
         {
            $this->data[ 'alpha' ] = null;
         }
         elseif ( $this->data[ 'opacity' ] == 100 )
         {
            $this->data[ 'alpha' ] = 0;
         }
         elseif ( $this->data[ 'opacity' ] == 0 )
         {
            $this->data[ 'alpha' ] = 127;
         }
         else
         {
            $this->data[ 'alpha' ] = ( 127 * ( 100 - $this->data[ 'opacity' ] ) ) / 100;
         }
      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   M E T H O D S   - - - - - - - - - - - - - - - - - - - - - -">

      # <editor-fold defaultstate="collapsed" desc="G E T T E R">

      /**
       * Gibt die RGB-Werte als numerisch indiziertes Array (3 Elemente) zurueck.
       *
       * @return array 0=Red 1=Green 2=Blue
       */
      public final function getRGB()
      {
         return array(
            $this->data[ 'red' ],
            $this->data[ 'green' ],
            $this->data[ 'blue' ]
         );
      }

      /**
       * Gibt den Alphakanal und die RGB-Werte als numerisch indiziertes Array
       * (4 Elemente) zurueck.
       *
       * @return array 0=Alpha 1=Red 2=Green 3=Blue
           */
      public final function getARGB()
      {
         return array(
            $this->data[ 'alpha' ],
            $this->data[ 'red' ],
            $this->data[ 'green' ],
            $this->data[ 'blue' ]
         );
      }

      /**
       * Gibt die RGB-Werte und den Alphakanal als numerisch indiziertes Array
       * (4 Elemente) zurueck.
       *
       * @return array 0=Red 1=Green 2=Blue 3=Alpha
       */
      public final function getRGBA()
      {
         return array(
            $this->data[ 'red' ],
            $this->data[ 'green' ],
            $this->data[ 'blue' ],
            $this->data[ 'alpha' ]
         );
      }

      /**
       * Returns the red RGB color part.
       *
       * @return integer
       */
      public final function getR()
      {
         return $this->data[ 'red' ];
      }

      /**
       * Returns the green RGB color part.
       *
       * @return integer
       */
      public final function getG()
      {
         return $this->data[ 'green' ];
      }

      /**
       * Returns the blue RGB color part.
       *
       * @return mixed
       */
      public final function getB()
      {
         return $this->data[ 'blue' ];
      }

      /**
       * @return integer
       */
      public final function getAlpha()
      {
         return \is_null( $this->data[ 'alpha' ] ) ? 0 : $this->data[ 'alpha' ];
      }

      /**
       * @return integer
       */
      public final function getOpacity()
      {
         return \is_null( $this->data[ 'opacity' ] ) ? 100 : $this->data[ 'opacity' ];
      }

      /**
       * @return string
       */
      public final function getHexadecimal()
      {
         return $this->$this->data[ 'hex' ];
      }

      /**
       * @param $name
       * @return array|bool|int|mixed|string
       */
      public function __get( $name )
      {
         return $this->get( $name );
      }

      /**
       * @param $name
       * @return array|bool|int|mixed|string
       */
      protected function get($name)
      {
         switch (strtolower($name))
         {
            case 'r': case 'red':     return $this->getR();
            case 'g': case 'green':   return $this->getG();
            case 'b': case 'blue':    return $this->getB();
            case 'alpha': case 'a':   return $this->getAlpha();
            case 'opacity': case 'o': return $this->getOpacity();
            case 'rgb':               return $this->getRGB();
            case 'rgba':              return $this->getRGBA();
            case 'argb':              return $this->getARGB();
            case 'hex': case 'h': case 'hexadecimal':
                                      return $this->getHexadecimal();
            default:                  return false;
         }
      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc="S E T T E R">

      /**
       * Sets a new color, defined by a valid RGB value.
       *
       * If a string is used the following formats are valid: 'rgb(r,g,b)' or 'r,g,b'
       *
       * Or a array (0=r,1=g,2=b) or assoviative with keys 'r'|'red', 'g'|'green', 'b'|'blue'
       *
       * @param  string|array $rgbValue
       * @throws \BF\ArgumentFormatException
       */
      public function setRGB( $rgbValue )
      {
         if ( \is_string( $rgbValue ) )
         {
            $this->setRGBString( $rgbValue );
         }
         elseif ( \is_array( $rgbValue ) && \count( $rgbValue ) > 2 )
         {
            $this->setRGBArray( $rgbValue );
         }
         else
         {
            throw new \BF\ArgumentFormatException(
               'rgbValue',
               $rgbValue,
               'Illegal RGB-Value Format!'
            );
         }
      }

      /**
       * @param array $argbValue
       * @return bool
       * @throws \BF\ArgumentFormatException
       */
      public function setARGB( array $argbValue )
      {
         if ( \is_string( $argbValue ) )
         {
            $this->setARGBString( $argbValue );
            return true;
         }
         if ( \is_array( $argbValue ) && \count( $argbValue ) > 2 )
         {
             $this->setARGBArray( $argbValue );
             return true;
         }
         throw new \BF\ArgumentFormatException(
            'argbValue',
            $argbValue,
            'Illegal ARGB-Value Format!'
         );
      }

      /**
       * @param array $rgbaValue
       * @return bool
       * @throws \BF\ArgumentFormatException
       */
      public function setRGBA( array $rgbaValue )
      {
         if ( \is_string( $rgbaValue ) )
         {
            $this->setRGBAString( $rgbaValue );
            return true;
         }
         if ( \is_array( $rgbaValue ) && \count( $rgbaValue ) > 2 )
         {
            $this->setRGBAArray( $rgbaValue );
            return true;
         }
         throw new \BF\ArgumentFormatException(
            'rgbaValue',
            $rgbaValue,
            'Illegal RGBA-Value Format!'
         );
      }

      /**
       * @param  integer $redValue
       * @throws \BF\ArgumentFormatException
       */
      public function setR( $redValue )
      {
         if ( $redValue < 0 || $redValue > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'redValue',
               $redValue,
              'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         $this->data[ 'red' ] = $redValue;
         $this->data[ 'hex' ] = \BF\Drawing\ColorTool::Rgb2Hex(
            $this->data[ 'red' ],
            $this->data[ 'green' ],
            $this->data[ 'blue' ]
         );
      }

      /**
       * @param  integer $greenValue
       * @throws \BF\ArgumentFormatException
       */
      public function setG( $greenValue )
      {
         if ( $greenValue < 0 || $greenValue > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'greenValue',
               $greenValue,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         $this->data[ 'green' ] = $greenValue;
         $this->data[ 'hex' ] = \BF\Drawing\ColorTool::Rgb2Hex(
            $this->data[ 'red' ],
            $this->data[ 'green' ],
            $this->data[ 'blue' ]
         );
      }

      /**
       * @param  integer $blueValue
       * @throws \BF\ArgumentFormatException
       */
      public function setB( $blueValue )
      {
         if ( $blueValue < 0 || $blueValue > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'blueValue',
               $blueValue,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         $this->data[ 'blue' ] = $blueValue;
         $this->data[ 'hex' ]  = \BF\Drawing\ColorTool::Rgb2Hex(
            $this->data[ 'red' ],
            $this->data[ 'green' ],
            $this->data[ 'blue' ]
         );
      }

      /**
       * @param string $colorDefinition
       */
      public function setWebColor( $colorDefinition )
      {
         $rgb = \BF\Drawing\ColorTool::Color2Rgb( $colorDefinition );
         $this->data[ 'red' ]     = $rgb[ 0 ];
         $this->data[ 'green' ]   = $rgb[ 1 ];
         $this->data[ 'blue' ]    = $rgb[ 2 ];
         $this->data[ 'alpha' ]   = 0;
         $this->data[ 'opacity' ] = 100;
         $this->data[ 'hex' ]     = \BF\Drawing\ColorTool::Rgb2Hex(
            $this->data[ 'red' ],
            $this->data[ 'green' ],
            $this->data[ 'blue' ]
         );
      }

      /**
       * @param  integer $value
       * @throws \BF\ArgumentFormatException
       */
      public function setAlpha( $value = null )
      {
         if ( \is_null( $value ) )
         {
            $this->data[ 'alpha' ]   = null;
            $this->data[ 'opacity' ] = null;
            return;
         }
         if ( $value < 0 || $value > 127 )
         {
            throw new \BF\ArgumentFormatException(
               'value',
               $value,
               'Illegal alpha value outside the allowed range 0-127.'
            );
         }
         $this->data[ 'alpha' ] = $value;
         if ( $this->data[ 'alpha' ] == 0 )
         {
            $this->data[ 'opacity' ] = 100;
         }
         elseif ( $this->data[ 'alpha' ] == 127 )
         {
            $this->data[ 'opacity' ] = 0;
         }
         else
         {
            $this->data[ 'opacity' ] = \intval( \floor( ( $this->data[ 'alpha' ] * 100 ) / 127 ) );
         }
      }

      /**
       * @param  integer $value
       * @throws \BF\ArgumentFormatException
       */
      public function setOpacity( $value = null )
      {
         if ( \is_null( $value ) )
         {
            $this->data[ 'alpha' ] = null;
            $this->data[ 'opacity' ] = null;
            return;
         }
         if ( $value < 0 || $value > 100 )
         {
            throw new \BF\ArgumentFormatException(
               'value',
               $value,
               'Illegal opacity value outside the allowed range 0-100.'
            );
         }
         $this->data[ 'opacity' ] = $value;
         if ( $this->data[ 'opacity' ] == 100 )
         {
            $this->data[ 'alpha' ] = 0;
         }
         elseif ( $this->data[ 'opacity' ] == 0 )
         {
            $this->data[ 'alpha' ] = 127;
         }
         else
         {
            $this->data[ 'alpha' ] = ( 127 * ( 100 - $this->data[ 'opacity' ] ) ) / 100;
         }
      }

      /**
       * @param $name
       * @param $value
       */
      public function __set( $name, $value )
      {
         $this->set( $name, $value );
      }

      /**
       * @param $name
       * @param $value
       */
      protected function set( $name, $value )
      {
         switch ( \strtolower( $name ) )
         {
            case 'rgb':
               $this->setRGB( $value );
               break;
            case 'argb':
               $this->setARGB( $value );
               break;
            case 'rgba':
               $this->setRGBA( $value );
               break;
            case 'r':
            case 'red':
               $this->setR( $value );
               break;
            case 'g':
            case 'green':
               $this->setG( $value );
               break;
            case 'b':
            case 'blue':
               $this->setB( $value );
               break;
            case 'hex':
            case 'hexadecimal':
            case 'value':
            case 'webcolor':
               $this->setWebColor( $value );
               break;
            case 'alpha':
            case 'a':
               $this->setAlpha( $value );
               break;
            case 'o':
            case 'opacity':
               $this->setOpacity( $value );
               break;
         }
      }

      # </editor-fold>

      /**
       * @return string
       */
      public function __toString()
      {
         return $this->data[ 'hex' ];
      }

      /**
       * @return array
       */
      public function toArray()
      {
         return $this->data;
      }

      /**
       * @return number
       */
      public function createGdValue()
      {
         if ( \is_null( $this->getAlpha() ) )
         {
            return \hexdec(
               \str_pad( \dechex( $this->Red ), 2, 0, \STR_PAD_LEFT )
             . \str_pad( \dechex( $this->Green ), 2, 0, \STR_PAD_LEFT )
             . \str_pad( \dechex( $this->Blue ), 2, 0, \STR_PAD_LEFT )
            );
         }
         return \bindec(
            \decbin(  $this->getAlpha()  ) . \decbin(  \hexdec( \substr($this->Hex, 1) )  )
         );
      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   S T A T I C   M E T H O D S   - - - - - - - - - - - - - - -">

      /**
       * Inits a new instance from defined string.
       *
       * @param  string $objectString
       * @return \BF\Drawing\Color
       */
      public static function FromString( $objectString )
      {
         if ( false !== ( $rgb = \BF\Drawing\ColorTool::Color2Rgb( $objectString ) ) )
         {
            return new \BF\Drawing\Color(
               \BF\Drawing\ColorTool::Rgb2Hex(
                  $rgb[ 0 ],
                  $rgb[ 1 ],
                  $rgb[ 2 ]
               )
            );
         }
         if ( false !== ( $hex = self::RgbStringToHex( $objectString ) ) )
         {
            return new \BF\Drawing\Color( $hex );
         }
         return false;
      }

      /**
       * Inits a new instance from defined array.
       *
       * @param  array $objectData
       * @return \BF\Drawing\Color Or boolean FALSE
       */
      public static function FromArray( array $objectData )
      {
         if ( \count( $objectData ) == 3 )
         {
            if ( false !== ( $hex = \BF\Drawing\ColorTool::Color2Hex( $objectData ) ) )
            {
               return new \BF\Drawing\Color( $hex );
            }
         }
         $rgb = array();
         if ( isset( $objectData[ 'r' ] ) )
         {
            $rgb[ 0 ] = \intval( $objectData[ 'r' ] );
         }
         elseif ( isset( $objectData[ 'red' ] ) )
         {
            $rgb[ 0 ] = \intval( $objectData[ 'red' ] );
         }
         elseif ( isset( $objectData[ 'Red' ] ) )
         {
            $rgb[ 0 ] = \intval( $objectData[ 'Red' ] );
         }
         else
         {
            return false;
         }
         if ( isset( $objectData[ 'g' ] ) )
         {
            $rgb[ 1 ] = \intval( $objectData[ 'g' ] );
         }
         elseif ( isset( $objectData[ 'green' ] ) )
         {
            $rgb[ 1 ] = \intval( $objectData[ 'green' ] );
         }
         elseif ( isset( $objectData[ 'Green' ] ) )
         {
            $rgb[ 1 ] = \intval( $objectData[ 'Green' ] );
         }
         else
         {
            return false;
         }
         if ( isset( $objectData[ 'b' ] ) )
         {
            $rgb[ 2 ] = \intval( $objectData[ 'b' ] );
         }
         elseif ( isset( $objectData[ 'blue' ] ) )
         {
            $rgb[ 2 ] = \intval( $objectData[ 'blue' ] );
         }
         elseif ( isset( $objectData[ 'Blue' ] ) )
         {
            $rgb[ 2 ] = \intval( $objectData[ 'Blue' ] );
         }
         else
         {
            return false;
         }
         if ( false !== ( $hex = \BF\Drawing\ColorTool::Rgb2Hex( $rgb ) ) )
         {
            return new \BF\Drawing\Color( $hex );
         }
         return false;
      }

      /**
       * Wandelt einen Integer-Wert, der eine Farbe mit Alphaangabe repraesentiert
       * (siehe imagecolorallocatealpha()) in eine \BF\Drawing\Color Instanz
       *
       * @param  int $gdValueWithAlpha
       * @return \BF\Drawing\Color
       */
      public static function FromGdValueWithAlpha( $gdValueWithAlpha )
      {
         $a = ( $gdValueWithAlpha >> 24 ) & 0xFF;
         $r = ( $gdValueWithAlpha >> 16 ) & 0xFF;
         $g = ( $gdValueWithAlpha >> 8 )  & 0xFF;
         $b = $gdValueWithAlpha & 0xFF;
         if ( $a == 0 )
         {
            $o = 0;
         }
         elseif ( $a == 127 )
         {
            $o = 100;
         }
         else
         {
            $o = \intval( \floor( ( 100 * $a ) / 127 ) );
         }
         return new \BF\Drawing\Color( array( $r, $g, $b ), $o );
      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P R O T E C T E D   S T A T I C   M E T H O D S   - - - - - - - - - - - -">

      /**
       * @param  string  $rgbString
       * @return boolean
       */
      protected static function RgbStringToHex( $rgbString )
      {
         #$r = $b = $g = 0;
         $m = null;
         if ( \preg_match( '~^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$~', $rgbString, $m ) )
         {
            $r = \intval( $m[ 1 ] );
            $g = \intval( $m[ 2 ] );
            $b = \intval( $m[ 3 ] );
         }
         elseif ( \preg_match( '~^argb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$~', $rgbString, $m ) )
         {
            $r = \intval( $m[ 2 ] );
            $g = \intval( $m[ 3 ] );
            $b = \intval( $m[ 4 ] );
         }
         else
         {
            return false;
         }
         if ( $r < 0 ) { $r = 0; }
         if ( $r > 255 ) { $r = 255; }
         if ( $g < 0 ) { $g = 0; }
         if ( $g > 255 ) { $g = 255; }
         if ( $b < 0 ) { $b = 0; }
         if ( $b > 255 ) { $b = 255; }
         return \BF\Drawing\ColorTool::Rgb2Hex( $r, $g, $b );
      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P R I V A T E   M E T H O D S   - - - - - - - - - - - - - - - - - - - - -">

      /**
       * @param $rgbString
       * @throws \BF\ArgumentFormatException
       */
      private function setRGBString( $rgbString )
      {
         $m = null;
         if ( \preg_match( '~^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$~', $rgbString, $m ) )
         {
            $r = \intval( $m[ 1 ] );
            $g = \intval( $m[ 2 ] );
            $b = \intval( $m[ 3 ] );
         }
         elseif ( \preg_match('~^(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})$~', $rgbString, $m ) )
         {
            $r = \intval( $m[ 1 ] );
            $g = \intval( $m[ 2 ] );
            $b = \intval( $m[ 3 ] );
         }
         else
         {
            throw new \BF\ArgumentFormatException(
               'rgbString',
               $rgbString,
               "Illegal RGB-Value Format! You can use a formats like 'rgb(r,g,b)' or 'r,g,b'."
            );
         }
         if ( $r < 0 || $r > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'r',
               $r,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $g < 0 || $g > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'g',
               $g,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $b < 0 || $b > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'b',
               $b,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         $this->data[ 'red' ]   = $r;
         $this->data[ 'green' ] = $g;
         $this->data[ 'blue' ]  = $b;
         $this->data[ 'hex' ]   = \BF\Drawing\ColorTool::Rgb2Hex( $r, $g, $b );
      }

      /**
       * @param array $rgbValue
       * @throws \BF\ArgumentFormatException
       */
      private function setRGBArray( array $rgbValue )
      {
         if ( isset( $rgbValue[ 0 ] )
           && isset( $rgbValue[ 1 ] )
           && isset( $rgbValue[ 2 ] ) )
         {
            $r = \intval( $rgbValue[ 0 ] );
            $g = \intval( $rgbValue[ 1 ] );
            $b = \intval( $rgbValue[ 2 ] );
         }
         else
         {
            $rgbValue = \array_change_key_case( $rgbValue, \CASE_LOWER );
            if ( isset( $rgbValue[ 'r' ] )
              && isset( $rgbValue[ 'g' ] )
              && isset( $rgbValue[ 'b' ] ) )
            {
               $r = \intval( $rgbValue[ 'r' ] );
               $g = \intval( $rgbValue[ 'g' ] );
               $b = \intval( $rgbValue[ 'b' ] );
            }
            elseif ( isset( $rgbValue[ 'red' ] )
                  && isset( $rgbValue[ 'green' ] )
                  && isset( $rgbValue[ 'blue' ] ) )
            {
               $r = \intval( $rgbValue[ 'red' ] );
               $g = \intval( $rgbValue[ 'green' ] );
               $b = \intval( $rgbValue[ 'blue' ] );
            }
            else
            {
               throw new \BF\ArgumentFormatException(
                  'rgbValue',
                  $rgbValue,
                  "Illegal RGB-Value Format! You can use numeric indices (0=R 1=G 2=B) or a associative array with "
                . "caseless keys 'r'|'red', 'g'|'green', 'b'|'blue'"
               );
            }
         }
         if ( $r < 0 || $r > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'r',
               $r,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $g < 0 || $g > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'g',
               $g,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $b < 0 || $b > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'b',
               $b,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         $this->data[ 'red' ]   = $r;
         $this->data[ 'green' ] = $g;
         $this->data[ 'blue' ]  = $b;
         $this->data[ 'hex' ]   = \BF\Drawing\ColorTool::Rgb2Hex( $r, $g, $b );
      }

      /**
       * @param $argbValue
       * @throws \BF\ArgumentFormatException
       */
      private function setARGBString( $argbValue )
      {
         $m = null;
         $a = $r = $b = $g = 0;
         if ( \preg_match( '~^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$~', $argbValue, $m ) )
         {
            $r = \intval( $m[ 1 ] );
            $g = \intval( $m[ 2 ] );
            $b = \intval( $m[ 3 ] );
         }
         else if ( \preg_match( '~^argb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$~', $argbValue, $m ) )
         {
            $a = \intval( $m[ 1 ] );
            $r = \intval( $m[ 2 ] );
            $g = \intval( $m[ 3 ] );
            $b = \intval( $m[ 4 ] );
         }
         else
         {
            throw new \BF\ArgumentFormatException(
               'argbValue',
               $argbValue,
               "Illegal ARGB-Value Format! You can use a formats like 'rgb(r,g,b)' or 'argb(alpha,r,g,b)'."
            );
         }
         if ( $a < 0 || $a > 127 )
         {
            throw new \BF\ArgumentFormatException(
               'a',
               $a,
               'Illegal alpha value outside the allowed range 0-127.'
            );
         }
         if ( $r < 0 || $r > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'r',
               $r,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $g < 0 || $g > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'g',
               $g,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $b < 0 || $b > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'b',
               $b,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         $this->data[ 'red' ]   = $r;
         $this->data[ 'green' ] = $g;
         $this->data[ 'blue' ]  = $b;
         $this->data[ 'hex' ]   = \BF\Drawing\ColorTool::Rgb2Hex( $r, $g, $b );
         $this->data[ 'alpha' ] = $a;
         if ( $this->data[ 'alpha' ] == 0 )
         {
            $this->data[ 'opacity' ] = 100;
         }
         elseif ( $this->data[ 'alpha' ] == 127 )
         {
            $this->data[ 'opacity' ] = 0;
         }
         else
         {
            $this->data[ 'opacity' ] = \intval( \floor( ( $this->data['alpha'] * 100 ) / 127 ) );
         }
      }

      /**
       * @param array $argbValue
       * @throws \BF\ArgumentFormatException
       */
      private function setARGBArray( array $argbValue )
      {
         $a = $r = $b = $g = 0;
         if ( isset( $argbValue[ 0 ] )
           && isset( $argbValue[ 1 ] )
           && isset( $argbValue[ 2 ] ) )
         {
            if ( isset( $argbValue[ 3 ] ) )
            {
               $a = \intval( $argbValue[ 0 ] );
               $r = \intval( $argbValue[ 1 ] );
               $g = \intval( $argbValue[ 2 ] );
               $b = \intval( $argbValue[ 3 ] );
            }
            else
            {
               $r = \intval( $argbValue[ 0 ] );
               $g = \intval( $argbValue[ 1 ] );
               $b = \intval( $argbValue[ 2 ] );
            }
         }
         else
         {
             $argbValue = \array_change_key_case( $argbValue, \CASE_LOWER );
             if ( isset( $argbValue[ 'r' ] )
               && isset( $argbValue[ 'g' ] )
               && isset( $argbValue[ 'b' ] ) )
             {
               $r = \intval( $argbValue[ 'r' ] );
               $g = \intval( $argbValue[ 'g' ] );
               $b = \intval( $argbValue[ 'b' ] );
               if ( isset( $argbValue[ 'a' ] ) )
               {
                  $a = \intval( $argbValue[ 'a' ] );
               }
            }
            elseif ( isset( $argbValue[ 'red' ] )
                  && isset( $argbValue[ 'green' ] )
                  && isset( $argbValue[ 'blue' ] ) )
            {
               $r = \intval( $argbValue[ 'red' ] );
               $g = \intval( $argbValue[ 'green' ] );
               $b = \intval( $argbValue[ 'blue' ] );
               if ( isset( $argbValue[ 'alpha' ] ) )
               {
                  $a = \intval( $argbValue[ 'alpha' ] );
               }
            }
            else
            {
               throw new \BF\ArgumentFormatException(
                  'argbValue',
                  $argbValue,
                  "Illegal ARGB-Value Format! You can use numeric indices (0=R 1=G 2=B) or (0=A 1=R 2=G 3=B) or a "
                . "associative array with caseless keys 'r'|'red', 'g'|'green', 'b'|'blue' and 'a'|'alpha'"
               );
            }
         }
         if ( $a < 0 || $a > 127 )
         {
            throw new \BF\ArgumentFormatException(
               'a',
               $a,
               'Illegal alpha value outside the allowed range 0-127.'
            );
         }
         if ( $r < 0 || $r > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'r',
               $r,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $g < 0 || $g > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'g',
               $g,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $b < 0 || $b > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'b',
               $b,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         $this->data[ 'red' ]   = $r;
         $this->data[ 'green' ] = $g;
         $this->data[ 'blue' ]  = $b;
         $this->data[ 'hex' ]   = \BF\Drawing\ColorTool::Rgb2Hex( $r, $g, $b );
         $this->data[ 'alpha' ] = $a;
         if ( $this->data[ 'alpha' ] == 0 )
         {
            $this->data['opacity'] = 100;
         }
         elseif ( $this->data[ 'alpha' ] == 127 )
         {
            $this->data['opacity'] = 0;
         }
         else
         {
            $this->data[ 'opacity' ] = \intval( \floor( ( $this->data['alpha'] * 100 ) / 127 ) );
         }
      }

      /**
       * @param $rgbaValue
       * @throws \BF\ArgumentFormatException
       */
      private function setRGBAString( $rgbaValue )
      {
         $m = null;
         $a = $r = $b = $g = 0;
         if ( \preg_match( '~^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$~', $rgbaValue, $m ) )
         {
            $r = \intval( $m[ 1 ] );
            $g = \intval( $m[ 2 ] );
            $b = \intval( $m[ 3 ] );
         }
         else if ( \preg_match( '~^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$~', $rgbaValue, $m ) )
         {
            $r = \intval( $m[ 2 ] );
            $g = \intval( $m[ 3 ] );
            $b = \intval( $m[ 4 ] );
            $a = \intval( $m[ 1 ] );
         }
         else
         {
            throw new \BF\ArgumentFormatException(
               'rgbaValue',
               $rgbaValue,
               "Illegal RGBA-Value Format! You can use a formats like 'rgb(r,g,b)' or 'rgba(r,g,b,alpha)'."
            );
         }
         if ( $a < 0 || $a > 127 )
         {
            throw new \BF\ArgumentFormatException(
               'a',
               $a,
               'Illegal alpha value outside the allowed range 0-127.'
            );
         }
         if ( $r < 0 || $r > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'r',
               $r,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $g < 0 || $g > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'g',
               $g,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $b < 0 || $b > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'b',
               $b,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         $this->data[ 'red' ]   = $r;
         $this->data[ 'green' ] = $g;
         $this->data[ 'blue' ]  = $b;
         $this->data[ 'hex' ]   = \BF\Drawing\ColorTool::Rgb2Hex( $r, $g, $b );
         $this->data[ 'alpha' ] = $a;
         if ( $this->data[ 'alpha' ] == 0 )
         {
            $this->data['opacity'] = 100;
         }
         elseif ( $this->data[ 'alpha' ] == 127 )
         {
            $this->data['opacity'] = 0;
         }
         else
         {
            $this->data[ 'opacity' ] = \intval( \floor( ( $this->data['alpha'] * 100 ) / 127 ) );
         }
      }

      /**
       * @param array $rgbaValue
       * @throws \BF\ArgumentFormatException
       */
      private function setRGBAArray( array $rgbaValue )
      {
         $a = $r = $b = $g = 0;
         if ( isset( $rgbaValue[ 0 ] )
           && isset( $rgbaValue[ 1 ] )
           && isset( $rgbaValue[ 2 ] ) )
         {
            if ( isset( $rgbaValue[ 3 ] ) )
            {
               $a = \intval( $rgbaValue[ 0 ] );
               $r = \intval( $rgbaValue[ 1 ] );
               $g = \intval( $rgbaValue[ 2 ] );
               $b = \intval( $rgbaValue[ 3 ] );
            }
            else
            {
               $r = \intval( $rgbaValue[ 0 ] );
               $g = \intval( $rgbaValue[ 1 ] );
               $b = \intval( $rgbaValue[ 2 ] );
            }
         }
         else
         {
            $rgbaValue = \array_change_key_case( $rgbaValue,\CASE_LOWER );
            if ( isset( $rgbaValue[ 'r' ] )
              && isset( $rgbaValue[ 'g' ] )
              && isset( $rgbaValue[ 'b' ] ) )
            {
               $r = \intval( $rgbaValue[ 'r' ] );
               $g = \intval( $rgbaValue[ 'g' ] );
               $b = \intval( $rgbaValue[ 'b' ] );
               if ( isset( $rgbaValue[ 'a' ] ) )
               {
                  $a = \intval( $rgbaValue[ 'a' ] );
               }
            }
            elseif ( isset( $rgbaValue[ 'red' ] )
                  && isset( $rgbaValue[ 'green' ] )
                  && isset( $rgbaValue[ 'blue' ] ) )
            {
               $r = \intval( $rgbaValue[ 'red' ] );
               $g = \intval( $rgbaValue[ 'green' ] );
               $b = \intval( $rgbaValue[ 'blue' ] );
               if ( isset( $rgbaValue[ 'alpha' ] ) )
               {
                  $a = \intval( $rgbaValue[ 'alpha' ] );
               }
            }
            else
            {
               throw new \BF\ArgumentFormatException(
                  'rgbaValue',
                  $rgbaValue,
                  "Illegal RGBA-Value Format! You can use numeric indices (0=R 1=G 2=B) or (0=R 1=G 2=B 3=A) or a"
                . " associative array with caseless keys 'r'|'red', 'g'|'green', 'b'|'blue' and 'a'|'alpha'"
               );
            }
         }
         if ( $a < 0 || $a > 127 )
         {
            throw new \BF\ArgumentFormatException(
               'a',
               $a,
               'Illegal alpha value outside the allowed range 0-127.'
            );
         }
         if ( $r < 0 || $r > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'r',
               $r,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $g < 0 || $g > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'g',
               $g,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         if ( $b < 0 || $b > 255 )
         {
            throw new \BF\ArgumentFormatException(
               'b',
               $b,
               'Illegal r|g|b value outside the allowed range 0-255.'
            );
         }
         $this->data[ 'red' ]   = $r;
         $this->data[ 'green' ] = $g;
         $this->data[ 'blue' ]  = $b;
         $this->data[ 'hex' ]   = \BF\Drawing\ColorTool::Rgb2Hex( $r, $g, $b );
         $this->data[ 'alpha' ] = $a;
         if ( $this->data[ 'alpha' ] == 0 )
         {
            $this->data['opacity'] = 100;
         }
         elseif ( $this->data[ 'alpha' ] == 127 )
         {
            $this->data['opacity'] = 0;
         }
         else
         {
            $this->data[ 'opacity' ] = \intval( \floor( ( $this->data['alpha'] * 100 ) / 127 ) );
         }
      }

      # </editor-fold>

    }

}

